﻿using System;
using System.Collections.Generic;
using ClientResource.Scripts.Core;

namespace Pisces
{
	/**
	 * 有限状态机引擎
     * created by wangqiang
    **/
	public abstract class AbstractFSMEngine<T, S> where S : Enum
	{
		/**
		 * 状态机的拥有者
		 */
		private T owner; 
		/**
		 * 此状态机下的所有状态实现map
         * key:state, value:实现类
         */
        private Dictionary<S, AbstractFSMState<T, S>> allStatImpl;
        
		/**
		 * 当前状态
         */
        private AbstractFSMState<T, S> currentState;

        /**
         * 预转换到的下一个状态
         */
        private AbstractFSMState<T, S> nextState;

        /**
         * 转换关系
         */
        private FSMTransitionRelation<S> transitionRelation;

        /**
         * 当前状态的持续时间,单位毫秒
         */
        private int stateDuration = 0;

        public T getOwner()
        {
			return owner;
		}

		private AbstractFSMEngine()
		{
		}

		/**
         * 重置状态超时时间
         */
        public void resetStateDuration()
        {
			this.stateDuration = 0;
		}

		/**
		 * 构造方法
		 * @param owner 拥有者
		 * @param initialState 初始化的第一个状态
		 */
        public AbstractFSMEngine(T owner, S initialState)
        {
            allStatImpl = new Dictionary<S, AbstractFSMState<T, S>>();
            transitionRelation = new FSMTransitionRelation<S>();
            this.owner = owner;
            buildStateImpl();
            buildTransitionRelation();
            this.currentState = allStatImpl[initialState];
            if (this.currentState == null)
            {
                PiscesLog.error(string.Format("状态机初始化未找到初始化状态:{0}的实现类", initialState));
            }
        }

        /**
         * 构建所有的状态实现map
         */
        protected abstract void buildStateImpl();

        /**
         * 构建所有的状态转换关系
         */
        protected abstract void buildTransitionRelation();

        /**
         * 获取状态实现对象实例
         * @param state
         */
        public AbstractFSMState<T, S> getStateImpl(S state)
        {
            return allStatImpl.GetValueOrDefault(state);
        }

        /**
         * 增加一个状态实现
         * @param state
         * @param stateImpl
         */
        public void addStateImpl(S state, AbstractFSMState<T, S> stateImpl)
        {
            allStatImpl.Add(state, stateImpl);
        }

        /**
         * 增加一个转换关系
         * @param source
         * @param destination
         */
        public void addTransitionRelation(S source, params S[] destinations)
        {
            S[] destinationArray = destinations;
            if(destinationArray == null)
            {
                return;
            }
            for (int i = 0, iSize = destinationArray.Length; i < iSize; i++)
            {
                S s = destinationArray[i];
                transitionRelation.addTransition(source, s);
            }
        }

        /**
         * 当前帧转换到指定状态
         * @param destination 目标状态
         * @return 0:成功  负数:错误码
         */
        public int transitionTo(S destination)
        {
            S current = currentState.StateEnum;
            if(current.Equals(destination))
            {
                return 0;
            }

            AbstractFSMState<T, S> stateImpl = getStateImpl(destination);

            if (nextState != null)
            {
                if (!nextState.StateEnum.Equals(stateImpl.StateEnum))
                {
                    PiscesLog.warn(string.Format("状态转换错误,已有下一帧转换的操作, 当前状态:{0}, 转换状态:{1}, 帧修改的状态:{2}, ",
                        currentState, destination, nextState));
                    return (int)CoreErrorCode.FSM_TRANSITION_CONFLICT_STATE;
                }
            }
            else
            {
                nextState = stateImpl;
            }

            if (!canTransitionTo(currentState, destination))
            {
                return (int)CoreErrorCode.FSM_TRANSITION_CANNOT_TRANSITION;
            }

            currentState.leave(owner, nextState.StateEnum);

            // 放在leave和enter中间，这样在enter中就可以继续转换下一个状态了，但是在
            // leave中转换是不允许的，因为刚离开上一个状态还没有转换到下一个状态就又切换，在逻辑上是不合理的
            AbstractFSMState<T, S> next = nextState;
            currentState = nextState;
            nextState = null;

            onStateTransited(current,next.StateEnum);

            stateDuration = 0;
            next.enter(owner, current);
            
            return 0;
        }

        protected void onStateTransited(S current, S next)
        {

        }


        /**
         * 是否可以转换到目标状态
         * @param currentState
         * @param destination
         * @return
         */
        private bool canTransitionTo(AbstractFSMState<T,S> currentState, S destination)
        {
            bool result = transitionRelation.canTransitionTo(currentState.StateEnum, destination);
            if (!result)
            {
                return result;
            }

            result = currentState.canTransitionTo(owner, destination);
            return result;
        }

        /**
         * tick处理
         * @param interval
         */
        public void tick(int interval)
        {
        // 处理下一帧模式的状态转换
            if (nextState != null)
            {
            // 需要转换
                int result = transitionTo(nextState.StateEnum);
                if (result < 0)
                {
                    PiscesLog.warn(string.Format("tick处理状态转换失败, 当前状态:{0} 转换状态:{1} 错误码:{2}", currentState.StateEnum,
                        nextState.StateEnum, result));
                }
            }
            else
            {
                stateDuration += interval;
                if (stateDuration >= currentState.getTimeout())
                {
                    // 超时,只通知一次,然后清零继续重新计时
                    currentState.timeout(owner);
                    stateDuration = 0;
                }
                currentState.tick(owner, interval);
            }

        }

        /**
         * 获取当前状态枚举
         * @return
         */
        public S getCurrentState()
        {
            if (currentState == null)
            {
                return default(S);
            }

            return currentState.StateEnum;
        }
		
	}
}